package com.zsc.oj.zojcodesendbox.judge.python;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.zsc.oj.zojcodesendbox.judge.CodeSendBox;
import com.zsc.oj.zojcodesendbox.judge.ExecuteCodeRequest;
import com.zsc.oj.zojcodesendbox.judge.ExecuteCodeResponse;
import com.zsc.oj.zojcodesendbox.judge.JudgeInfo;
import com.zsc.oj.zojcodesendbox.utils.ProcessUtils;
import com.zsc.oj.zojcodesendbox.utils.model.ExecuteMessage;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
public class PythonNativeCodeSendBoxTemplate implements CodeSendBox {

    public static final String GLOBAL_DIR_NAME = "tempCode";
    public static final String FILE_NAME_PYTHON = "Main.py";

    @Override
    public ExecuteCodeResponse ExecuteCode(ExecuteCodeRequest executeCodeRequest) {
        String code = executeCodeRequest.getCode();
        List<String> inputList = executeCodeRequest.getInputList();

        //1、保存用户提交的代码
        File userCodeFile = saveUserCode(code);

        //2、运行代码（python语言不需要编译代码）
        List<ExecuteMessage> executeMessageList = runCode(userCodeFile, inputList);

        //3、收集整理的输出结果
        ExecuteCodeResponse executeCodeResponse = collectionResponse(executeMessageList);

        //4、清理文件
        boolean b = deleteFile(userCodeFile);
        if(b){
            log.info("删除成功");
        }else{
            log.error("删除失败");
        }

        return executeCodeResponse;
    }

    /**
     * 保存用户代码
     * @param UserCode：用户代码
     * @return
     */
    public File saveUserCode(String UserCode){
        //定位到项目的根目录
        String RootUrl = System.getProperty("user.dir");
        //在根目录下创建一个tempCode文件夹用来存放用户代码
        String globalPathName = RootUrl + File.separator + GLOBAL_DIR_NAME;

        //如果tempCode文件夹不存在，则创建一个
        if(!FileUtil.exist(globalPathName)){
            FileUtil.mkdir(globalPathName);
        }

        //通过UUID把用户的代码隔离存放，因为每个用户提交的代码都是main函数
        String codeParentPathName = globalPathName + File.separator + UUID.randomUUID();
        //将用户代码文件写入tempCode文件夹中
        File file = FileUtil.writeString(UserCode, codeParentPathName + File.separator + FILE_NAME_PYTHON, StandardCharsets.UTF_8);
        return file;
    }

    /**
     * 运行python代码
     * @param userCodefile
     * @return
     */
    public List<ExecuteMessage> runCode(File userCodefile, List<String> inputList){
        String path = userCodefile.getAbsolutePath();
        //python 语言中在window系统使用的Python，而在Linux系统中使用Python3
        String osName = System.getProperty("os.name").toLowerCase();
        System.out.println("当前操作系统：" + osName);
        String pythonCmdPrefix = "python3";
        if(osName.contains("win")){
            pythonCmdPrefix = "python";
        }

        List<ExecuteMessage> executeMessageList = new ArrayList<>();
        //拼接执行命令
        //window 上运行python文件的命令：python my_script.py
        //Linux 上运行python文件的命令：python3 my_script.py
        for (String input : inputList) {
            String runCmd = String.format("%s %s %s",pythonCmdPrefix,path,input);
            try{
                Process process = Runtime.getRuntime().exec(runCmd);
                ExecuteMessage executeMessage = ProcessUtils.getProcessMessage(process, "运行");
                executeMessageList.add(executeMessage);
            }catch (Exception e){
                ExecuteMessage executeMessage = new ExecuteMessage();
                executeMessage.setExitValue(1);
                executeMessage.setErrorMessage(e.getMessage());
                executeMessageList.add(executeMessage);
            }
        }
        return executeMessageList;
    }

    /**
     * 收集整理输出结果
     * @param executeMessageList
     * @return
     */
    public ExecuteCodeResponse collectionResponse(List<ExecuteMessage> executeMessageList){
        ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();
        List<String> outputList = new ArrayList<>();
        //选用最大值，便于判断是否超时
        long maxTime = 0;
        for (ExecuteMessage executeMessage : executeMessageList) {
            //如果运行时发生错误
            String errorMessage = executeMessage.getErrorMessage();
            if(StrUtil.isNotBlank(errorMessage)){
                executeCodeResponse.setMessage(errorMessage);
                executeCodeResponse.setStatus(3);
                break;
            }
            //将运行的正确信息设置到outputList
            outputList.add(executeMessage.getSuccessMessage());
            //超时时间
            Long time = executeMessage.getTime();
            if(time != null){
                maxTime = Math.max(maxTime,time);
            }
        }
        if(outputList.size() == executeMessageList.size()){
            executeCodeResponse.setStatus(1);
        }

        executeCodeResponse.setOutputList(outputList);

        JudgeInfo judgeInfo = new JudgeInfo();
        judgeInfo.setTime(maxTime);
        executeCodeResponse.setJudgeInfo(judgeInfo);

        return executeCodeResponse;
    }

    /**
     * 删除文件
     * @param userCodeFile
     * @return
     */
    public boolean deleteFile(File userCodeFile){
        if(userCodeFile.getParentFile() != null){
            boolean del = FileUtil.del(userCodeFile);
            if(del){
                System.out.println("删除成功");
                return true;
            }else{
                System.out.println("删除失败");
                return false;
            }
        }
        return true;
    }

}
